﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.IO;
using System.Security.Cryptography;

namespace Rugicon
{
    /// <summary>
    /// Emoticons service that pulls the data from the file system.
    /// </summary>
    public class FileEmoticonService : IEmoticonService
    {
        /// <summary>
        /// Raised when the user added or removed emoticons from the Rugicon data folder.
        /// </summary>
        public event EventHandler<EventArgs> EmoticonsChanged;

        /// <summary>
        /// Used for being notified when the user adds or removes its emoticons.
        /// </summary>
        private FileSystemWatcher fileWatcher;

        public FileEmoticonService()
        {
            // "Inject" the emoticons path.
            EmoticonsFolder = Path.Combine(AppDomain.CurrentDomain.BaseDirectory, @"Data\Emoticons");
            
            // Make sure data directory exists.
            Directory.CreateDirectory(EmoticonsFolder);

            // Set up the emoticons monitoring.
            // Look for all files below the Rugicon data emoticons folder.
            fileWatcher = new FileSystemWatcher();
            fileWatcher.Path = EmoticonsFolder;
            fileWatcher.Created += (s, e) => { OnEmoticonsChanged(); };
            fileWatcher.Deleted += (s, e) => { OnEmoticonsChanged(); };
            fileWatcher.Renamed += (s, e) => { OnEmoticonsChanged(); };
            fileWatcher.NotifyFilter = NotifyFilters.DirectoryName | NotifyFilters.FileName | NotifyFilters.CreationTime;
            fileWatcher.IncludeSubdirectories = true;
            fileWatcher.EnableRaisingEvents = true;
        }

        /// <summary>
        /// Folder where the emoticons set are stored.
        /// </summary>
        public string EmoticonsFolder { get; set; }

        /// <summary>
        /// Called when the user added or removed emoticons from the Rugicon data emoticons folder.
        /// </summary>
        protected void OnEmoticonsChanged()
        {
            if (this.EmoticonsChanged != null)
                EmoticonsChanged(this, new EventArgs());
        }

        /// <summary>
        /// Returns the available emoticon sets from the Rugicon data emoticons folder.
        /// </summary>
        /// <returns></returns>
        public IEnumerable<EmoticonSet> GetEmoticonSets()
        {
            // Make sure emoticons folder exists
            if(!Directory.Exists(EmoticonsFolder))
                Directory.CreateDirectory(EmoticonsFolder);

            // The set of emoticon set (result)
            var emoticonSets = new List<EmoticonSet>();

            // Each subdirectory is a emoticon set, and the root
            // is the special set "Your own emoticons".
            var emoticonSetFolders = new List<string> { EmoticonsFolder };
            emoticonSetFolders.AddRange(Directory.GetDirectories(EmoticonsFolder));

            // Create and populate each set.
            foreach (string setFolder in emoticonSetFolders)
            {
                // Get the emoticon images.
                // Only PNG, GIF, BMP or JPG.
                var pngEmoticons = Directory.GetFiles(setFolder, "*.png", SearchOption.TopDirectoryOnly);
                var gifEmoticons = Directory.GetFiles(setFolder, "*.gif", SearchOption.TopDirectoryOnly);
                var bmpEmoticons = Directory.GetFiles(setFolder, "*.bmp", SearchOption.TopDirectoryOnly);
                var jpgEmoticons = Directory.GetFiles(setFolder, "*.jpg", SearchOption.TopDirectoryOnly);
                var emoticons = pngEmoticons.Union(gifEmoticons).Union(bmpEmoticons).Union(jpgEmoticons);

                // Check if there is any emoticon in this set
                if (emoticons.Count() < 1)
                    continue;

                // Create the set
                var emoticonSet = new EmoticonSet();

                // The name, by now, is the folder name. 
                emoticonSet.Name = new DirectoryInfo(setFolder).Name;

                // I know this is so ugly... set the appropiate name 
                // to the special set. Encapsulating the foreach block this
                // can be prettier.
                if (emoticonSetFolders.IndexOf(setFolder) == 0)
                    emoticonSet.Name = "Your own emoticons";

                // Add the set to the result
                emoticonSets.Add(emoticonSet);

                // Calculate the hash for each emoticon
                foreach (string rawEmoticonFile in emoticons)
                {
                    using (var md5 = new MD5CryptoServiceProvider())
                    {
                        var hash = md5.ComputeFileHash(rawEmoticonFile);
                        emoticonSet.Emoticons.Add(new Emoticon
                        {
                            Filename = rawEmoticonFile,
                            Hash = hash
                        });
                    }
                }
            }

            return emoticonSets;
        }

        public void Dispose()
        {
            fileWatcher.Dispose();
        }
    }
}
